package com.example.cursor.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.cursor.entity.Account;
import com.example.cursor.entity.TransactionRecord;
import com.example.cursor.mapper.AccountMapper;
import com.example.cursor.service.AccountService;
import com.example.cursor.dto.TransferDTO;
import com.example.cursor.mapper.TransactionRecordMapper;
import com.example.cursor.config.TransferLimitConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.cursor.exception.BusinessException;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {
    
    @Autowired
    private TransactionRecordMapper transactionRecordMapper;
    
    @Autowired
    private TransferLimitConfig transferLimitConfig;
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TransactionRecord transfer(TransferDTO transferDTO) {
        
        // 1. 检查转账限额
        checkTransferLimit(transferDTO);
        
        // 2. 参数校验
        if (transferDTO.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("INVALID_AMOUNT", "转账金额必须大于0");
        }
        
        // 2. 查询转出和转入账户
        Account fromAccount = this.getById(transferDTO.getFromAccountId());
        Account toAccount = this.getById(transferDTO.getToAccountId());
        
        if (fromAccount == null || toAccount == null) {
            throw new BusinessException("ACCOUNT_NOT_FOUND", "账户不存在");
        }
        
        // 3. 检查余额
        if (fromAccount.getBalance().compareTo(transferDTO.getAmount()) < 0) {
            throw new BusinessException("INSUFFICIENT_BALANCE", "余额不足");
        }
        
        try {
            // 4. 扣减转出账户余额
            fromAccount.setBalance(fromAccount.getBalance().subtract(transferDTO.getAmount()));
            fromAccount.setUpdatedTime(LocalDateTime.now());
            this.updateById(fromAccount);
            
            // 5. 增加转入账户余额
            toAccount.setBalance(toAccount.getBalance().add(transferDTO.getAmount()));
            toAccount.setUpdatedTime(LocalDateTime.now());
            this.updateById(toAccount);
            
            // 6. 记录交易
            TransactionRecord record = TransactionRecord.builder()
                    .fromAccountId(transferDTO.getFromAccountId())
                    .toAccountId(transferDTO.getToAccountId())
                    .amount(transferDTO.getAmount())
                    .type("TRANSFER")
                    .status("SUCCESS")
                    .remark(transferDTO.getRemark())
                    .createdTime(LocalDateTime.now())
                    .build();
                    
            transactionRecordMapper.insert(record);
            
            return record;
        } catch (Exception e) {
            // 记录失败交易
            TransactionRecord record = TransactionRecord.builder()
                    .fromAccountId(transferDTO.getFromAccountId())
                    .toAccountId(transferDTO.getToAccountId())
                    .amount(transferDTO.getAmount())
                    .type("TRANSFER")
                    .status("FAILED")
                    .remark("转账失败：" + e.getMessage())
                    .createdTime(LocalDateTime.now())
                    .build();
            
            transactionRecordMapper.insert(record);
            
            if (e instanceof BusinessException) {
                throw e;
            }
            throw new BusinessException("TRANSFER_FAILED", "转账失败：" + e.getMessage());
        }
    }
    
    private void checkTransferLimit(TransferDTO transferDTO) {
        // 1. 检查单次限额
        if (transferDTO.getAmount().compareTo(transferLimitConfig.getSingleLimit()) > 0) {
            throw new BusinessException("TRANSFER_LIMIT", 
                "单次转账金额不能超过" + transferLimitConfig.getSingleLimit());
        }
        
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startOfDay = now.withHour(0).withMinute(0).withSecond(0).withNano(0);
        LocalDateTime startOfMonth = now.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
        
        // 2. 检查每日转账次数
        LambdaQueryWrapper<TransactionRecord> dailyQuery = new LambdaQueryWrapper<>();
        dailyQuery.eq(TransactionRecord::getFromAccountId, transferDTO.getFromAccountId())
                 .eq(TransactionRecord::getType, "TRANSFER")
                 .eq(TransactionRecord::getStatus, "SUCCESS")
                 .ge(TransactionRecord::getCreatedTime, startOfDay);
        
        long dailyCount = transactionRecordMapper.selectCount(dailyQuery);
        if (dailyCount >= transferLimitConfig.getDailyCount()) {
            throw new BusinessException("DAILY_LIMIT", 
                "当日转账次数已达上限：" + transferLimitConfig.getDailyCount() + "次");
        }
        
        // 3. 检查每月转账总额
        LambdaQueryWrapper<TransactionRecord> monthlyQuery = new LambdaQueryWrapper<>();
        monthlyQuery.eq(TransactionRecord::getFromAccountId, transferDTO.getFromAccountId())
                   .eq(TransactionRecord::getType, "TRANSFER")
                   .eq(TransactionRecord::getStatus, "SUCCESS")
                   .ge(TransactionRecord::getCreatedTime, startOfMonth);
        
        List<TransactionRecord> monthlyRecords = transactionRecordMapper.selectList(monthlyQuery);
        BigDecimal monthlyTotal = monthlyRecords.stream()
                .map(TransactionRecord::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
                
        if (monthlyTotal.add(transferDTO.getAmount()).compareTo(transferLimitConfig.getMonthlyLimit()) > 0) {
            throw new BusinessException("MONTHLY_LIMIT", 
                "当月转账总额不能超过" + transferLimitConfig.getMonthlyLimit());
        }
    }
    
    @Override
    public List<TransactionRecord> getTransactionRecords(Long accountId) {
        LambdaQueryWrapper<TransactionRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TransactionRecord::getFromAccountId, accountId)
                   .or()
                   .eq(TransactionRecord::getToAccountId, accountId)
                   .orderByDesc(TransactionRecord::getCreatedTime);
        
        return transactionRecordMapper.selectList(queryWrapper);
    }
} 